//=============================================================================
/**
 * @file	gym_sky.c
 * @brief	飛行ジムギミック
 * @author	Nozomu Saito
 *
 * モジュール名：GYM_
 */
//=============================================================================
#include "common.h"
#include "fieldsys.h"
#include "fieldmap_work.h"
#include "system/snd_tool.h"
#include "include/savedata/gimmickwork.h"
#include "../fielddata/build_model/build_model_id.h"

#include "field_gimmick_def.h"
#include "sysflag_def.h"

#include "gym_def.h"

#include "gym_local.h"
#include "gym_init.h"

#include "gym.h"
/**
#include "field/evwkdef.h"
#include "fielddata/script/saveflag.h"
#include "script.h"
*/
#include "pair_poke.h"

//=========================================================================================================
//=========================================================================================================

#define GRID_UNIT	(16)

//リフト位置定義
#define MODEL_SKY_LIFT_LV1	(FX32_ONE*16*2)		//モデル高さ１段階
#define MODEL_SKY_LIFT_LV2	(FX32_ONE*16*31)	//モデル高さ２段階
#define SKY_LIFT_LV1	MODEL_SKY_LIFT_LV1			//高さ１段階
#define SKY_LIFT_LV2	MODEL_SKY_LIFT_LV2		//高さ２段階
#define SKY_LIFT_DIF	(FX32_ONE*16)			//高さ変動値（モデル高さ用）

#define SKY_GYM_DATA_HRIGHT_ID	(0)	//拡張高さ参照インデックス（飛行ジムリフト用）

#define SKY_GYM_EX_HEIGHT_X	(14)
#define SKY_GYM_EX_HEIGHT_Z	(19)
#define SKY_GYM_EX_HEIGHT_W	(3)
#define SKY_GYM_EX_HEIGHT_H	(3)

#define SKY_GYM_LIFT_POS_X	(15)
#define SKY_GYM_LIFT_POS_Z	(20)
#define SKY_GYM_LIFT_OFS	(8)

typedef struct {
	int seq;							///<シーケンス保持ワーク
	FIELDSYS_WORK *fsys;
}EVENT_GYM_WORK;

//飛行ジム
static BOOL GMEVENT_MoveUpGymSky(GMEVENT_CONTROL * event);
static BOOL GMEVENT_MoveDownGymSky(GMEVENT_CONTROL * event);
static void SkyGymLiftUpTcb(TCB_PTR tcb, void *work);
static void SkyGymLiftDownTcb(TCB_PTR tcb, void *work);

//////////////////////////////////////////////////////////////////////////////////////////

//飛行ジム
//エッジマーキングテーブル
static const GXRgb EdgeColorSkyGym[8] = {
    GX_RGB(0, 0, 0),
    GX_RGB(9, 9, 9),
    GX_RGB(16, 11, 4),
    GX_RGB(20, 28, 31),
    GX_RGB(4, 4, 4),
    GX_RGB(4, 4, 4),
    GX_RGB(4, 4, 4),
    GX_RGB(4, 4, 4)
};
//---------------------------------------------------------------------------
/**
 * @brief	飛行ジム:セットアップ
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_SetupSkyGym(FIELDSYS_WORK *fsys)
{
	u8 lift;
	M3DO_PTR ptr;
	fx32 model_lift_height;
	fx32 data_height;
	GIMMICKWORK *work;
	SKY_GYM_WORK *sky_gym_work;

	//ここでギミックワークの中身を見る
	work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
	sky_gym_work = (SKY_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_SKY_GYM);

	//リフトの作成
	{
		VecFx32 vec = {	FX32_ONE*(GRID_UNIT*SKY_GYM_LIFT_POS_X+SKY_GYM_LIFT_OFS),
						0,
						FX32_ONE*(GRID_UNIT*SKY_GYM_LIFT_POS_Z+SKY_GYM_LIFT_OFS)};
		M3DO_SetMap3DObjExp(fsys->Map3DObjExp,
							BMID_ROOM_GYM01_LIFT,
							&vec, NULL,
							fsys->field_3d_anime );//<リフト
	}

	//拡張高さの作成
	EXH_SetUpExHeightData(	SKY_GYM_DATA_HRIGHT_ID,
							SKY_GYM_EX_HEIGHT_X,
							SKY_GYM_EX_HEIGHT_Z,
							SKY_GYM_EX_HEIGHT_W,
							SKY_GYM_EX_HEIGHT_H,
							SKY_LIFT_LV1,fsys->ExHeightList );

	//リフトの位置を取得
	lift = sky_gym_work->Lift;

	switch(lift){
	case GYM_SKY_LIFT_LV1:		//下フロア
		model_lift_height = MODEL_SKY_LIFT_LV1;
		data_height = SKY_LIFT_LV1;
		break;
	case GYM_SKY_LIFT_LV2:		//上フロア
		model_lift_height = MODEL_SKY_LIFT_LV2;
		data_height = SKY_LIFT_LV2;
		break;
	default:	//データが壊れている可能性がある
		GF_ASSERT(0 && "データが不正です");
		model_lift_height = MODEL_SKY_LIFT_LV1;
		data_height = SKY_LIFT_LV1;
	}

	//リフトOBJを取得
	ptr = M3DO_GetMap3DObjDataFromID(fsys->Map3DObjExp, BMID_ROOM_GYM01_LIFT);
	//モデルのy座標変更
	{
		VecFx32 vec;
		vec = M3DO_GetGlobalVec(ptr);
		vec.y = model_lift_height;
		M3DO_SetGlobalVec(ptr, &vec);
	}

	//
	//高さデータの変更
	EXH_SetExHeight( SKY_GYM_DATA_HRIGHT_ID, data_height, fsys->ExHeightList );

	//飛行ジム用エッジマーキング
	G3X_SetEdgeColorTable(EdgeColorSkyGym);
}

//---------------------------------------------------------------------------
/**
 * @brief	飛行ジム:リフト移動
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_MoveSkyGymLift(FIELDSYS_WORK *fsys)
{
	EVENT_GYM_WORK * egw;

	//イベントコール
	egw = sys_AllocMemoryLo(HEAPID_WORLD, sizeof(EVENT_GYM_WORK));
	egw->seq = 0;
	egw->fsys = fsys;

	//自機のy座標からコールするイベントを切り替える
	{
		VecFx32 vec;
		GIMMICKWORK *work;
		SKY_GYM_WORK *sky_gym_work;
		work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
		sky_gym_work = (SKY_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_SKY_GYM);
		Player_VecPosGet( fsys->player, &vec );
		if (vec.y == SKY_LIFT_LV1){
			FieldEvent_Call(fsys->event, GMEVENT_MoveUpGymSky, egw);
			sky_gym_work->Lift = GYM_SKY_LIFT_LV2;
		}else{
			FieldEvent_Call(fsys->event, GMEVENT_MoveDownGymSky, egw);
			sky_gym_work->Lift = GYM_SKY_LIFT_LV1;
		}
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	飛行ジム:リフトを上げる
 *
 * @param	event	イベントポインタ
 *
 * @return	BOOL TRUE:イベント終了	FALSE:イベント継続
 */
//---------------------------------------------------------------------------
static BOOL GMEVENT_MoveUpGymSky(GMEVENT_CONTROL * event)
{
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EVENT_GYM_WORK * egw = FieldEvent_GetSpecialWork(event);

	switch (egw->seq) {
	case 0:
		//連れ歩きポケモンアニメ終了待ち
		FieldEvent_Call(fsys->event, PairPokeEvAnm_WaitAnmEvent, NULL);
		(egw->seq) ++;
		break;
	case 1:
		//TCB作成（フィールドOBJより速く処理されるようにプライオリティを決定する）
		TCB_Add(SkyGymLiftUpTcb, egw, 0);
		(egw->seq) ++;
		break;
	case 5:
		sys_FreeMemoryEz(egw);
		return TRUE;
	}
	return FALSE;
}

//---------------------------------------------------------------------------
/**
 * @brief	飛行ジム:リフトを下げる
 *
 * @param	event	イベントポインタ
 *
 * @return	BOOL TRUE:イベント終了	FALSE:イベント継続
 */
//---------------------------------------------------------------------------
static BOOL GMEVENT_MoveDownGymSky(GMEVENT_CONTROL * event)
{
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EVENT_GYM_WORK * egw = FieldEvent_GetSpecialWork(event);

	switch (egw->seq) {
	case 0:
		//連れ歩きポケモンアニメ終了待ち
		FieldEvent_Call(fsys->event, PairPokeEvAnm_WaitAnmEvent, NULL);
		(egw->seq) ++;
		break;
	case 1:
		//TCB作成（フィールドOBJより速く処理されるようにプライオリティを決定する）
		TCB_Add(SkyGymLiftDownTcb, egw, 0);
		(egw->seq) ++;
		break;
	case 5:
		sys_FreeMemoryEz(egw);
		return TRUE;
	}
	return FALSE;
}

//---------------------------------------------------------------------------
/**
 * @brief	飛行ジム:リフトを上げるタスク
 *
 * @param	tcb		TCBポインタ
 * @param	work	ワークポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void SkyGymLiftUpTcb(TCB_PTR tcb, void *work)
{
	EVENT_GYM_WORK * egw = work;
	FIELDSYS_WORK * fsys = egw->fsys;
	switch (egw->seq) {
	case 2:
		Player_HeightGet_ON_OFF( fsys->player, FALSE );//自機の高さ自動取得をオフ

		//リフト音再生
		Snd_SePlay( SEQ_SE_DP_ELEBETA );
		(egw->seq) ++;
		break;
	case 3:	//リフトを上昇
		{
			M3DO_PTR ptr;
			//リフトOBJを取得
			ptr = M3DO_GetMap3DObjDataFromID(fsys->Map3DObjExp, BMID_ROOM_GYM01_LIFT);
			//y座標変更
			{
				VecFx32 vec, player_vec;
				vec = M3DO_GetGlobalVec(ptr);
				vec.y += SKY_LIFT_DIF;

				if (vec.y >= MODEL_SKY_LIFT_LV2){	//セット終了
					vec.y = MODEL_SKY_LIFT_LV2;
					//リフト音停止
					Snd_SeStopBySeqNo( SEQ_SE_DP_ELEBETA, 0 );
					(egw->seq) ++;
				}
				Player_VecPosGet( fsys->player, &player_vec );
				player_vec.y += SKY_LIFT_DIF;
				Player_VecPosYSet( fsys->player, player_vec.y );	//自機高さ変更
				//連れ歩きいるなら、連れ歩き高さ変更
				PairPoke_SetVecPosY(fsys, player_vec.y);
				//リフト座標更新
				M3DO_SetGlobalVec(ptr, &vec);
			}
		}
		break;
	case 4:	//高さセット
		EXH_SetExHeight( SKY_GYM_DATA_HRIGHT_ID, SKY_LIFT_LV2, fsys->ExHeightList );
		//自機の高さ自動取得をオン
		Player_HeightGetSet_ON_OFF( fsys->player, TRUE );

		//リフト移動終了音
		Snd_SePlay( SE_YOSUGA_GYM_LIFT );
		//タスク削除
		TCB_Delete(tcb);
		(egw->seq) ++;
		break;
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	飛行ジム:リフトを下げるタスク
 *
 * @param	tcb		TCBポインタ
 * @param	work	ワークポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void SkyGymLiftDownTcb(TCB_PTR tcb, void *work)
{
	EVENT_GYM_WORK * egw = work;
	FIELDSYS_WORK * fsys = egw->fsys;
	switch (egw->seq) {
	case 2:
		Player_HeightGet_ON_OFF( fsys->player, FALSE );//自機の高さ自動取得をオフ

		//リフト音再生
		Snd_SePlay( SEQ_SE_DP_ELEBETA );
		(egw->seq)	++;
		break;
	case 3:	//リフトを下降
		{
			M3DO_PTR ptr;
			//リフトOBJを取得
			ptr = M3DO_GetMap3DObjDataFromID(fsys->Map3DObjExp, BMID_ROOM_GYM01_LIFT);
			//y座標変更
			{
				VecFx32 vec, player_vec;
				vec = M3DO_GetGlobalVec(ptr);
				vec.y -= SKY_LIFT_DIF;

				if (vec.y <= MODEL_SKY_LIFT_LV1){	//セット終了
					vec.y = MODEL_SKY_LIFT_LV1;
					//リフト音停止
					Snd_SeStopBySeqNo( SEQ_SE_DP_ELEBETA, 0 );
					(egw->seq) ++;
				}
				Player_VecPosGet( fsys->player, &player_vec );
				player_vec.y -= SKY_LIFT_DIF;
				Player_VecPosYSet( fsys->player, player_vec.y );	//自機高さ変更
				//連れ歩きいるなら、連れ歩き高さ変更
				PairPoke_SetVecPosY(fsys,  player_vec.y);
				//リフト座標更新
				M3DO_SetGlobalVec(ptr, &vec);
			}
		}
		break;
	case 4:	//高さセット
		EXH_SetExHeight( SKY_GYM_DATA_HRIGHT_ID, SKY_LIFT_LV1, fsys->ExHeightList );
		//自機の高さ自動取得をオン
		Player_HeightGetSet_ON_OFF( fsys->player, TRUE );

		//リフト移動終了音
		Snd_SePlay( SE_YOSUGA_GYM_LIFT );
		//タスク削除
		TCB_Delete(tcb);
		(egw->seq) ++;
		break;
	}
}